// TODO(andreas): Conceptually these should go to `re_data_source`.
// However, `re_data_source` depends on everything that _implements_ a datasource, therefore we would get a circular dependency!

use re_log_encoding::RrdManifest;
use re_log_types::{AbsoluteTimeRange, LogMsg, StoreId, TableMsg, TimelineName, impl_into_enum};

/// Message from a data source.
///
/// May contain limited UI commands for instrumenting the state of the receiving end.
#[derive(Clone, Debug)]
pub enum DataSourceMessage {
    /// The index of all the chunks in a recording.
    ///
    /// Some sources may send this, others may not.
    RrdManifest(StoreId, Box<RrdManifest>),

    /// See [`LogMsg`].
    LogMsg(LogMsg),

    /// See [`TableMsg`].
    TableMsg(TableMsg),

    /// A UI command that has to be ordered relative to [`LogMsg`]s.
    ///
    /// Non-ui receivers can safely ignore these.
    UiCommand(DataSourceUiCommand),
}

impl_into_enum!(LogMsg, DataSourceMessage, LogMsg);
impl_into_enum!(TableMsg, DataSourceMessage, TableMsg);
impl_into_enum!(DataSourceUiCommand, DataSourceMessage, UiCommand);

impl DataSourceMessage {
    /// The name of the variant, useful for error message etc
    pub fn variant_name(&self) -> &'static str {
        match self {
            Self::RrdManifest { .. } => "RrdManifest",
            Self::LogMsg(_) => "LogMsg",
            Self::TableMsg(_) => "TableMsg",
            Self::UiCommand(_) => "UiCommand",
        }
    }

    // We sometimes inject meta-data for latency tracking etc
    pub fn insert_arrow_record_batch_metadata(&mut self, key: String, value: String) {
        match self {
            Self::LogMsg(log_msg) => log_msg.insert_arrow_record_batch_metadata(key, value),
            Self::TableMsg(table_msg) => table_msg.insert_arrow_record_batch_metadata(key, value),
            Self::RrdManifest { .. } | Self::UiCommand(_) => {
                // Not everything needs latency tracking
            }
        }
    }
}

/// UI commands issued when streaming in datasets.
///
/// If you're not in a ui context you can safely ignore these.
#[derive(Clone, Debug)]
pub enum DataSourceUiCommand {
    /// Mark a time range as valid.
    ///
    /// Everything outside can still be navigated to, but will be considered potentially lacking some data and therefore "invalid".
    /// Visually, it is outside of the normal time range and shown greyed out.
    ///
    /// If timeline is `None`, this signals that all timelines are considered to be valid entirely.
    AddValidTimeRange {
        store_id: StoreId,

        /// If `None`, signals that all timelines are entirely valid.
        timeline: Option<TimelineName>,
        time_range: AbsoluteTimeRange,
    },

    /// Navigate to time/entities/anchors/etc. that are set in a `re_uri::Fragment`.
    SetUrlFragment {
        store_id: StoreId,

        /// Uri fragment, see `re_uri::Fragment` on how to parse it.
        // Not using `re_uri::Fragment` to avoid further dependency entanglement.
        fragment: String, //re_uri::Fragment,
    },
}
